#ifndef SKYNET_H
#define SKYNET_H

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <memory.h>
#include <time.h>
#include <sys/time.h>
#include <fstream>
#include <cstring>

#include "hls_stream.h"
#include "ap_int.h"

// #define DEBUG
#ifndef DEBUG
#define sds_alloc malloc
#define sds_free free
typedef int DT;
typedef ap_int<8> ADT;
typedef ap_int<19> BDT;
typedef ap_int<6> WDT;
typedef ap_int<19> MDT;
typedef ap_int<256> ADT32;
typedef ap_uint<256> WDT32;
typedef ap_uint<512> BDT16;
typedef ap_uint<256> BDT8;
#else
typedef int DT;
#define sds_alloc malloc
#define sds_free free
typedef char ADT;
typedef int BDT;
typedef char WDT;
typedef int MDT;
struct DT32
{
    DT data[32];
};
struct ADT32
{
    ADT data[32];
};
struct BDT32
{
    BDT data[32];
};
struct MDT32
{
    MDT data[32];
};
struct WDT32
{
    WDT data[32];
};
struct BDT16
{
    BDT data[16];
};
struct BDT8
{
    BDT data[8];
};
struct MDT16
{
    BDT data[16];
};
#endif

#define na 8
#define nw 6
#define nb 16
#define nm 17

typedef int DT;

#define amin -128
#define amax 127

#define smin -262144
#define smax 262143

#define layer_count 19
#define check_scale 0.00001

struct layer
{
    char name[10];
    int iw, ih, ic, ow, oh, oc;
    int k, s, p;
};

#define pool1_offset 0
#define pool2_offset 105298
#define conv5_offset 145885
#define conv6_offset 186472
#define pool3_offset 267646
#define conv7_offset 289060
#define conv8_offset 331888
#define conv9_offset 374716
#define conv10_offset 417544
#define conv11_offset 474648
#define conv12_offset 617408
#define conv13_offset 620977
#define conv1_b 0
#define conv2_b 8
#define conv3_b 24
#define conv4_b 40
#define conv5_b 64
#define conv6_b 88
#define conv7_b 136
#define conv8_b 184
#define conv9_b 280
#define conv10_b 376
#define conv11_b 504
#define conv12_b 824
#define conv1_m 4
#define conv2_m 16
#define conv3_m 32
#define conv4_m 52
#define conv5_m 76
#define conv6_m 112
#define conv7_m 160
#define conv8_m 232
#define conv9_m 328
#define conv10_m 440
#define conv11_m 664
#define conv12_m 836
#define conv1_w 0
#define conv2_w 9
#define conv3_w 73
#define conv4_w 91
#define conv5_w 283
#define conv6_w 310
#define conv7_w 886
#define conv8_w 940
#define conv9_w 3244
#define conv10_w 3352
#define conv11_w 9496
#define conv12_w 9856
#define conv13_w 13696

/**********utils.cpp************/
void load_fm(ADT *fm, layer l);
void load_weight(WDT32 *weight, int length);
void load_biasm(BDT8 *biasm, int length);
void check(ADT *result, ADT *golden, int len, layer l);
void check_fm(ADT *fm, layer l);
void check_bbox(BDT *bbox, layer l);
void show_fm(ADT *fm, layer l);

void generate_fm(DT *fm, layer l);
void generate_weight(DT *weight, layer l);

/**********transform.cpp************/
void stitch(ADT *ifm[4], ADT *ofm, layer l);
void distitch(ADT *ifm, ADT *ofm[4], layer l);
void fm_DT_2_DT32(ADT *in, ADT32 *out, layer l);
void fm_DT32_2_DT(ADT32 *in, ADT *out, layer l);
void distitch_bbox(BDT *ifm, BDT *ofm[4], layer l);
void bbox_DT16_2_DT(BDT16 *in, BDT *out, layer l);
void bbox_DT8_2_DT(BDT8 *in, BDT *out, layer l);

/**********convolution.cpp [HW]************/
void POOL(hls::stream<ADT> IFM_stream[32], hls::stream<BDT> OFM_stream[32]);
void ACTIVATION(hls::stream<BDT> IFM_stream[32], hls::stream<ADT> OFM_stream[32], BDT BBUF[32], MDT MBUF[32]);

/**********CONV.cpp [HW]************/
void PWCONV1X1(
    hls::stream<ADT> IFM_stream[32],
    hls::stream<BDT> OFM_stream[32],
    const WDT WBUF1x1[32][32]
#ifdef USE_DSP
    ,
    bool ap_clk_div2
#endif
);

void DWCONV3X3(hls::stream<ADT> IFM_stream[32], hls::stream<BDT> OFM_stream[32], const WDT WBUF3x3[32][3][3]);

/**********SkyNet.h [HW]************/
void SkyNet(ADT32 *ifm, ADT32 *ofm, WDT32 *weight, BDT8 *biasm, BDT8 *bbox);

#endif